// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
// ReSharper disable StringLiteralTypo
// ReSharper disable UnusedParameter.Local

/*
 * Ars Magna project, http://arsmagna.ru
 */

#region Using directives

using System;
using System.Text;
using System.Drawing;

using AM.Reporting.Utils;

#endregion

#nullable enable

namespace AM.Reporting.Barcode
{
    /// <summary>
    /// Generates the UPC E0 barcode.
    /// </summary>
    public class BarcodeUPC_E0 : BarcodeEAN
    {
        // UPC E Parity Pattern Table , Number System 0
        internal static string[,] tabelle_UPC_E0 =
        {
            { "E", "E", "E", "o", "o", "o" }, // 0
            { "E", "E", "o", "E", "o", "o" }, // 1
            { "E", "E", "o", "o", "E", "o" }, // 2
            { "E", "E", "o", "o", "o", "E" }, // 3
            { "E", "o", "E", "E", "o", "o" }, // 4
            { "E", "o", "o", "E", "E", "o" }, // 5
            { "E", "o", "o", "o", "E", "E" }, // 6
            { "E", "o", "E", "o", "E", "o" }, // 7
            { "E", "o", "E", "o", "o", "E" }, // 8
            { "E", "o", "o", "E", "o", "E" } // 9
        };

        internal override void DrawText (IGraphics g, string barData)
        {
            DrawString (g, -8, -2, "0", true);

            // parts of pattern: 3 + 24 + 6
            var x1 = GetWidth (pattern.Substring (0, 3));
            var x2 = GetWidth (pattern.Substring (0, 3 + 24));
            DrawString (g, x1, x2, barData.Substring (0, 6));

            x1 = GetWidth (pattern) + 1;
            x2 = x1 + 7;
            DrawString (g, x1, x2, barData.Substring (6, 1), true);
        }

        internal override string GetPattern()
        {
            text = DoCheckSumming (text, 7);
            var c = CharToInt (text[6]);

            // Startcode
            var result = "A0A";

            for (var i = 0; i <= 5; i++)
            {
                if (tabelle_UPC_E0[c, i] == "E")
                {
                    for (var j = 0; j <= 3; j++)
                    {
                        result += tabelle_EAN_C[CharToInt (text[i])][3 - j];
                    }
                }
                else
                {
                    result += tabelle_EAN_A[CharToInt (text[i])];
                }
            }

            // Stopcode
            result += "0A0A0A";
            return result;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BarcodeUPC_E0"/> class with default settings.
        /// </summary>
        public BarcodeUPC_E0()
        {
            extra1 = 8;
            extra2 = 8;
        }
    }

    /// <summary>
    /// Generates the UPC E1 barcode.
    /// </summary>
    public class BarcodeUPC_E1 : BarcodeUPC_E0
    {
        internal override string GetPattern()
        {
            text = DoCheckSumming (text, 7);
            var c = CharToInt (text[6]);

            // Startcode
            var result = "A0A";
            for (var i = 0; i <= 5; i++)
            {
                if (tabelle_UPC_E0[c, i] == "E")
                {
                    result += tabelle_EAN_A[CharToInt (text[i])];
                }
                else
                {
                    for (var j = 0; j <= 3; j++)
                    {
                        result += tabelle_EAN_C[CharToInt (text[i])][3 - j];
                    }
                }
            }

            // Stopcode
            result += "0A0A0A";
            return result;
        }
    }

    /// <summary>
    /// Generates the UPC A barcode.
    /// </summary>
    public class BarcodeUPC_A : BarcodeUPC_E0
    {
        internal override void DrawText (IGraphics g, string barData)
        {
            DrawString (g, -8, -2, barData.Substring (0, 1), true);

            // parts of pattern: 7 + 20 + 5 + 20 + 7
            var x1 = GetWidth (pattern.Substring (0, 7));
            var x2 = GetWidth (pattern.Substring (0, 7 + 20));
            DrawString (g, x1, x2, barData.Substring (1, 5));

            x1 = GetWidth (pattern.Substring (0, 7 + 20 + 5));
            x2 = GetWidth (pattern.Substring (0, 7 + 20 + 5 + 20));
            DrawString (g, x1, x2, barData.Substring (6, 5));

            x1 = GetWidth (pattern) + 1;
            x2 = x1 + 7;
            DrawString (g, x1, x2, barData.Substring (11, 1), true);
        }

        internal override string GetPattern()
        {
            text = DoCheckSumming (text, 12);

            //Startcode
            var result = "A0A";
            for (var i = 0; i <= 5; i++)
            {
                var code = tabelle_EAN_A[CharToInt (text[i])];
                result += i == 0 ? MakeLong (code) : code;
            }

            //Trennzeichen
            result += "0A0A0";
            for (var i = 6; i <= 11; i++)
            {
                var code = tabelle_EAN_C[CharToInt (text[i])];
                result += i == 11 ? MakeLong (code) : code;
            }

            //Stopcode
            return result + "A0A";
        }
    }

    /// <summary>
    /// Generates the 2-digit supplement barcode.
    /// </summary>
    public class BarcodeSupplement2 : BarcodeUPC_E0
    {
        internal string getSupp (string Nr)
        {
            var sum = 0;
            var tmp = Nr.Substring (0, Nr.Length - 1);

            var fak = tmp.Length;

            for (var i = 0; i < tmp.Length; i++)
            {
                sum += int.Parse (tmp[i].ToString()) * ((fak % 2) == 0 ? 9 : 3);
                fak--;
            }

            sum = ((sum % 10) % 10) % 10;
            return tmp + sum.ToString();
        }

        internal override void DrawText (IGraphics g, string barData)
        {
            DrawString (g, 0, drawArea.Width, barData);
        }

        internal override string GetPattern()
        {
            text = SetLen (2);

            var i32 = int.Parse (text);
            string mS;

            switch (i32 % 4)
            {
                case 0:
                    mS = "oo";
                    break;
                case 1:
                    mS = "oE";
                    break;
                case 2:
                    mS = "Eo";
                    break;
                case 3:
                    mS = "EE";
                    break;
                default:
                    mS = "";
                    break;
            }

            var tmp = getSupp (text + "0");

            var result = "506"; // Startcode
            for (var i = 0; i <= 1; i++)
            {
                if (mS[i] == 'E')
                {
                    for (var j = 0; j <= 3; j++)
                    {
                        result += tabelle_EAN_C[CharToInt (tmp[i])][3 - j];
                    }
                }
                else
                {
                    result += tabelle_EAN_A[CharToInt (tmp[i])];
                }

                if (i < 1)
                {
                    result += "05"; // character delineator
                }
            }

            return result;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BarcodeSupplement2"/> class with default settings.
        /// </summary>
        public BarcodeSupplement2()
        {
            textUp = true;
            extra1 = 0;
            extra2 = 0;
        }
    }

    /// <summary>
    /// Generates the 5-digit supplement barcode.
    /// </summary>
    internal class BarcodeSupplement5 : BarcodeSupplement2
    {
        internal override string GetPattern()
        {
            text = SetLen (5);
            var tmp = getSupp (text + "0");
            var c = tmp[5];

            var result = "506"; // Startcode

            for (var i = 0; i <= 4; i++)
            {
                if (tabelle_UPC_E0[CharToInt (c), 1 + i] == "E")
                {
                    for (var j = 0; j <= 3; j++)
                    {
                        result += tabelle_EAN_C[CharToInt (tmp[i])][3 - j];
                    }
                }
                else
                {
                    result += tabelle_EAN_A[CharToInt (tmp[i])];
                }

                if (i < 4)
                {
                    result += "05"; // character delineator
                }
            }

            return result;
        }
    }
}
